﻿#include"基于C++实现的项目.h"
// 1.日期计算机的实现
//日期合法性检查
bool Date::CheakDate() const
{
	if ((_month > 0 && _month < 13) && (_day > 0 && _day <= GetMonthDay(_year, _month)))
		return true;
	else
		return false;
}
//<<运算符重载
ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "/" << d._month << "/" << d._day << endl;
	return out;
}
//>>运算符重载
istream& operator>>(istream& in, Date& d)
{
	while (1)
	{
		cout << "请依次输入年/月/日";
		in >> d._year >> d._month >> d._day;
		if (!d.CheakDate())
		{
			cout << "日期非法！请重新输入";
			d.Print();
		}
		else
			break;
	}
	return in;
}
// 全缺省的构造函数
Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
	if (!CheakDate())
	{
		cout << "日期非法：";
		Print();
	}
}
// 拷贝构造函数
// d2(d1)
Date::Date(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}
// 赋值运算符重载
// d2 = d3 -> d2.operator=(&d2, d3)
Date& Date::operator=(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
	return *this;
}
// 析构函数
Date::~Date()
{
	;//由于Date类没有指向资源，故这里可以不用执行什么东西
}
// 日期+=天数
Date& Date::operator+=(int day)
{
	if (day < 0)//day<0,+=时相当于-=(-day)
	{
		return *this -= (-day);
	}
	_day += day;
	while (_day > GetMonthDay(_year, _month))//---有隐式的this指针
	{
		_day -= GetMonthDay(_year, _month);
		++_month;
		if (_month == 13)
		{
			_month = 1;
			++_year;
		}
	}
	return *this;
}
// 日期+天数
Date Date::operator+(int day) const
{
	Date tmp = *this;
	tmp += day;
	return tmp;
}
// 日期-=天数
Date& Date::operator-=(int day)
{
	if (day < 0)//day<0,-=时相当于+=(-day)
	{
		return *this += (-day);
	}
	_day -= day;
	while (_day <= 0)
	{
		--_month;
		if (_month == 0)
		{
			_month = 12;
			--_year;
		}
		_day += GetMonthDay(_year, _month);
	}
	return *this;
}
// 日期-天数
Date Date::operator-(int day) const
{
	Date tmp = *this;
	tmp -= day;
	return tmp;
}
// 前置++
Date& Date::operator++()
{
	*this += 1;
	return *this;
}
// 后置++
Date Date::operator++(int)
{
	Date tmp = *this;
	tmp += 1;
	return tmp;
}
// 前置--
Date& Date::operator--()
{
	*this -= 1;
	return *this;
}
// 后置--
Date Date::operator--(int)
{
	Date tmp = *this;
	tmp -= 1;
	return tmp;
}
// <运算符重载
bool Date::operator < (const Date& d) const
{
	//return *this - d < 0;//不能用日期-日期，下面日期-日期中调用了<,会造成反复来回调用
	if (_year < d._year)
		return true;
	else if (_year == d._year)
	{
		if (_month < d._month)
			return true;
		else if (_month == d._month)
		{
			return _day < d._day;
		}
	}
	return false;
}
// <=运算符重载
bool Date::operator<=(const Date& d) const
{
	return *this == d || *this < d;
}
// >运算符重载
bool Date::operator>(const Date& d) const//>的相反是<=,故 d1>d2 等价于 !(d1<=d2)
{
	return !(*this <= d);
}
// >=运算符重载
bool Date::operator>=(const Date& d) const//>=的相反是<,故 d1>=d2 等价于 !(d1<d2)
{
	return !(*this < d);
}
// ==运算符重载
bool Date::operator==(const Date& d) const
{
	return _year == d._year
		&& _month == d._month
		&& _day == d._day;
}
// !=运算符重载
bool Date::operator!=(const Date& d) const
{
	return !(*this == d);
}
// 日期-日期 返回天数
int Date::operator-(const Date& d) const
{
	int flag = 1;
	int ret = 0;
	Date max = *this;
	Date min = d;
	if (*this < d)
	{
		max = d;
		min = *this;
		flag = -1;
	}
	while (min < max)
	{
		++min;
		++ret;
	}
	return ret * flag;
}
void meun()
{
	Date d1; Date d2;
	cout << "请输入您要进行的操作" << endl;
	cout << "主要操作为：1.日期+=天数       2.日期-=天数" << endl;
	cout << "           3.日期-日期                   " << endl;
	int input = 0;
	cin >> input;
	int day;
	switch (input)
	{
	case 1:
		cout << "请输入你要加的日期和天数" << endl;
		cin >> d1;
		cin >> day;
		cout << (d1 += day);
		break;
	case 2:
		cout << "请输入你要减的日期和天数" << endl;
		cin >> d1;
		cin >> day;
		cout << (d1 -= day);
		break;
	case 3:
		cout << "请输入你要减的两个日期,必须是大日期在前，小日期在后的输入格式" << endl;
		cin >> d1 >> d2;
		//cin >> day;
		cout << (d1 - d2);
		break;
	default:
		cout << "你的选择有问题" << endl;
		break;
	}
}
int main()
{
	meun();
	return 0;
}


// 贪吃蛇的实现
namespace shuaiming
{
	//设置结点坐标
	inline void SetPos(short x, short y)
	{
		//获得标准输出设备的句柄
		HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
		//定位光标的位置
		COORD pos = { x,y };
		SetConsoleCursorPosition(houtput, pos);
	}
	//欢迎界面的打印
	void SnakeGame::WelcomeToGame()
	{
		SetPos(41, 15);
		wcout << L"欢迎来到贪吃蛇" << endl;
		SetPos(41, 21);
		system("pause");
		system("cls");
		SetPos(24, 15);
		wcout << L"用↑.↓.←.→来控制蛇的移动，按数字键盘的1加速，数字键盘的2减速" << endl;
		SetPos(24, 16);
		wcout << L"加速可以得到更高的分数" << endl;
		SetPos(41, 21);
		system("pause");
		system("cls");
	}
	//创建地图---即用墙体封闭部分空间
	void SnakeGame::CreateMap()//在这里
	{
		//上
		for (int i = 0; i < 29; i++)
			wcout << Wall;
		//下
		SetPos(0, 26);
		for (int i = 0; i < 29; i++)
			wcout << Wall;
		//左
		for (int i = 0; i <= 25; i++)
		{
			SetPos(0, i);
			wcout << Wall;
		}
		//右
		for (int i = 0; i <= 25; i++)
		{
			SetPos(56, i);
			wcout << Wall;
		}
	}
	//游戏的初始化
	void SnakeGame::GameStart()
	{
		//1.先设置窗口大小，再隐藏光标
		//设置窗口
		system("mode con cols=120 lines=44");
		system("title 贪吃蛇");
		HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
		//隐藏光标
		CONSOLE_CURSOR_INFO CursorInfo;
		GetConsoleCursorInfo(houtput, &CursorInfo);//获取界面光标信息
		CursorInfo.bVisible = false;//隐藏界面的光标
		SetConsoleCursorInfo(houtput, &CursorInfo);//设置界面光标状态
		//2.打印环境界面和功能介绍
		WelcomeToGame();
		//3.绘制地图
		CreateMap();
		//4.创建蛇
		InitSnakeBody();
		//5.创建食物
		CreateFood();
	}
	//打印蛇
	void SnakeGame::PrintSnakeBody()
	{
		auto it = SnakeBody.begin();
		while (it != SnakeBody.end())
		{
			SetPos(it->x, it->y);
			if (it == SnakeBody.begin())
				wcout << Head;//先蛇头
			else wcout << Body;//再蛇身
			++it;
		}
	}
	//初始化蛇身
	void SnakeGame::InitSnakeBody()
	{
		for (short i = 0; i < 5; i++)
		{
			NodePos n;
			n.x = X + 2 * i;
			n.y = Y;
			SnakeBody.push_front(n);
		}
		PrintSnakeBody();
	}
	//创建食物
	void SnakeGame::CreateFood()
	{
		short x, y;
		//由于宽字符与坐标的对应关系，要保证x坐标是偶数，蛇才能吃到食物
	next:
		do
		{
			x = rand() % 53 + 2;
			y = rand() % 25 + 1;
		} while (x % 2 != 0);
		//同时保证蛇身与食物坐标不能冲突
		auto it = SnakeBody.begin();
		while (it != SnakeBody.end())
		{
			if (x == it->x && y == it->y)//冲突就跳转,再去生成一个
				goto next;
			++it;
		}
		NodePos* food = new NodePos;
		food->x = x;
		food->y = y;
		SetPos(x, y);
		wcout << Food;
		_food = food;
	}
	//打印具体游戏说明信息
	void PrintHelpInfo()
	{
		SetPos(64, 14);
		wcout << L"不能穿墙，不能咬到自己" << endl;
		SetPos(64, 15);
		wcout << L"用 ↑. ↓ . ← . → 来控制蛇的移动";
		SetPos(64, 16);
		wcout << L"按数字键盘的1加速，数字键盘的2减速";
		SetPos(64, 17);
		wcout << L"按ESC退出游戏，按空格暂停游戏";
		SetPos(64, 18);
		wcout << L"帅明出版";
	}
	//游戏暂停
	void Pause()
	{
		while (1)
		{
			Sleep(2000);
			if (KEY_PRESS(VK_SPACE))//再次按空格则取消暂停
				break;
		}
	}
	//判断食物
	bool SnakeGame::NextIsFood(NodePos& n)
	{
		return (_food->x == n.x && _food->y == n.y);
	}
	//吃食物
	void SnakeGame::EatFood(NodePos& n)
	{
		SnakeBody.push_front(*(this->_food));
		//SnakeBody.pop_back();
		PrintSnakeBody();
		_score += _food_score;
		//吃掉食物后再重新创建
		CreateFood();
	}
	//不是食物就正常走
	void SnakeGame::NoFood(NodePos& next)
	{
		SnakeBody.push_front(next);
		auto it = SnakeBody.begin();
		int xx = 0;
		int yy = 0;
		while ((it++) != SnakeBody.end())
		{
			--it;
			SetPos(it->x, it->y);
			if (it == SnakeBody.begin())
				wcout << Head;//先蛇头
			else wcout << Body;//再蛇身
			xx = it->x;
			yy = it->y;
			++it;
			if (it == SnakeBody.end())
				break;
		}
		SetPos(xx, yy);
		wcout << L"  ";
		SnakeBody.pop_back();
	}
	//撞墙
	void SnakeGame::KillByWall()
	{
		auto it = SnakeBody.begin();//蛇头
		if (it->x == 0 || it->x == 56 || it->y == 0 || it->y == 26)
			_status = Kill_By_Wall;
	}
	//撞到自己
	void SnakeGame::KillBySelf()
	{
		//看头跟身体的坐标是否相同
		auto hit = SnakeBody.begin();
		auto it = SnakeBody.begin();
		++it;
		while (it != SnakeBody.end())
		{
			if (hit->x == it->x && hit->y == it->y)
			{
				_status = Kill_By_Self;
				break;
			}
			++it;
		}
	}
	//蛇每步的过程
	void SnakeGame::SnakeMove()
	{
		NodePos* next = new NodePos;//表示蛇下一步可能行为
		auto it = SnakeBody.begin();
		switch (_dir)
		{
		case Up:
			next->x = it->x;
			next->y = it->y - 1;
			break;
		case Down:
			next->x = it->x;
			next->y = it->y + 1;
			break;
		case Left:
			next->x = it->x - 2;
			next->y = it->y;
			break;
		case Right:
			next->x = it->x + 2;
			next->y = it->y;
			break;
		}
		//检测下一个坐标处是否是食物
		if (NextIsFood(*next))
			EatFood(*next);
		else
			NoFood(*next); //没有传递呀 
		//检测蛇是否撞墙
		KillByWall();
		//检测蛇是否撞到自己
		KillBySelf();
	}
	//运行游戏
	void SnakeGame::RunGame()
	{
		PrintHelpInfo();
		do
		{
			//打印总分数和食物的分数
			SetPos(64, 10);
			wcout << L"总分数：" << _score << endl;
			SetPos(64, 11);
			wprintf(L"当前食物的分数:%2d\n", _food_score);
			if (KEY_PRESS(VK_UP) && _dir != Down)//上键
				_dir = Up;
			else if (KEY_PRESS(VK_DOWN) && _dir != Up)//下键
				_dir = Down;
			else if (KEY_PRESS(VK_LEFT) && _dir != Right)//左键
				_dir = Left;
			else if (KEY_PRESS(VK_RIGHT) && _dir != Left)//右键
				_dir = Right;
			else if (KEY_PRESS(VK_SPACE))//空格键暂停
				Pause();
			else if (KEY_PRESS(VK_ESCAPE))//Esc键正常退出游戏
				_status = End_Normal;
			else if (KEY_PRESS(VK_NUMPAD1))//数字键盘的1加速
			{
				if (_sleep_time > 80)
				{
					_sleep_time -= 30;
					_food_score += 2;
				}
			}
			else if (KEY_PRESS(VK_NUMPAD2))//数字键盘的2减速
			{
				if (_food_score > 2)
				{
					_sleep_time += 30;
					_food_score -= 2;
				}
			}
			SnakeMove();//蛇的移动过程
			Sleep(_sleep_time);
		} while (_status == Ok);//状态为Ok则正常运行游戏
	}
	void gameLoop()
	{
		system("cls");
		shuaiming::SnakeGame s;
		s.GameStart();
		s.RunGame();
		s.GameEnd();
		shuaiming::SetPos(20, 15);
	}
	void playMusic()
	{
		shuaiming::Music();
	}
	void RunGame()
	{
		setlocale(LC_ALL, "");
		srand((unsigned int)time(nullptr));
		std::thread musicThread(playMusic);
		std::thread gameThread(gameLoop);
		musicThread.join();
		gameThread.join();
		while (getchar() != '\n');
		shuaiming::SetPos(0, 27);
	}
	bool Again_Yes_Or_No()
	{
		char ch = 0;
		do
		{
			shuaiming::SetPos(20, 15);
			wcout << L"再来一局吗?(Y/N):";
			cin >> ch;
			if (ch == 'Y' || ch == 'y')
			{
				RunGame();
				return true;
			}
			else return false;
			while (getchar() != '\n');
		} while (ch == 'Y' || ch == 'y');
		shuaiming::SetPos(0, 28);
		return false;
	}
	void Thanks()
	{
		shuaiming::SetPos(0, 28);
		wcout << L"游戏正式结束，感谢您对本游戏的支持" << endl;
		wcout << L"帅明出版，必是精品，先赞后用，养成习惯" << endl;
		exit(1);
	}
	//结束游戏
	void SnakeGame::GameEnd()
	{
		SetPos(24, 12);
		int i = 0;
		switch (_status)
		{
		case End_Normal:
			wcout << L"您主动结束游戏" << endl;
			Thanks();
		case Kill_By_Wall:
			wcout << L"您撞到墙上，游戏结束" << endl;
			do
			{
				i = Again_Yes_Or_No();
			} while (i);
			Thanks();
		case Kill_By_Self:
			wcout << L"您撞到了自己，游戏结束" << endl;
			do
			{
				i = Again_Yes_Or_No();
			} while (i);
			Thanks();
		}
	}
}

// 音乐
namespace shuaiming
{
	void Music()
	{
		HMIDIOUT handle;
		midiOutOpen(&handle, 0, 0, 0, CALLBACK_NULL);
		// midiOutShortMsg(handle, 2 << 8 | 0xC0);
		int volume = 0x7f;
		int voice = 0x0;
		int sleep = 350;
		int wind[] =
		{
		 400,0,L7,M1,M2,M3,300,L3,0,M5,M3,300,L2,L5,2,_,0,L7,M1,M2,M3,300,L2,0,M5,M3,M2,M3,M1,M2,L7,M1,300,L5,0,L7,M1,M2,M3,300,L3,0,M5,M3,300,L2,L5,2,_,0,L7,M1,M2,M3,300,L2,0,M5,M3,M2,M3,M1,M2,L7,M1,300,L5,
		 0,L7,M1,M2,M3,300,L3,0,M5,M3,300,L2,L5,2,_,0,L7,M1,M2,M3,300,L2,0,M5,M3,M2,M3,M1,M2,L7,M1,300,L5,0,L7,M1,M2,M3,300,L3,0,M5,M3,300,L2,L5,2,_,
		 0,M6,M3,M2,L6,M3,L6,M2,M3,L6,_,_,_,
		 M2,700,0,M1,300,M2,700,0,M1,300,M2,M3,M5,0,M3,700,300,M2,700,0,M1,300,M2,700,0,M1,M2,M3,M2,M1,300,L5,_,
		 M2,700,0,M1,300,M2,700,0,M1,300,M2,M3,M5,0,M3,700,300,M2,700,0,M3,300,M2,0,M1,700,300,M2,_,_,_,
		 M2,700,0,M1,300,M2,700,0,M1,300,M2,M3,M5,0,M3,700,300,M2,700,0,M3,300,M2,0,M1,700,300,L6,_,
		 0,M3,M2,M1,M2,300,M1,_,0,M3,M2,M1,M2,300,M1,700,0,L5,M3,M2,M1,M2,300,M1,_,_,_,
		 M1,M2,M3,M1,M6,0,M5,M6,300,_,700,0,M1,300,M7,0,M6,M7,300,_,_,M7,0,M6,M7,300,_,M3,0,H1,H2,H1,M7,300,M6,M5,M6,0,M5,M6,_,M5,M6,M5,300,M6,0,M5,M2,300,_,0,M5,700,300,M3,_,_,_,
		 M1,M2,M3,M1,M6,0,M5,M6,300,_,700,0,M1,300,M7,0,M6,M7,300,_,_,M7,0,M6,M7,300,_,M3,0,H1,H2,H1,M7,300,M6,M5,M6,0,H3,H3,300,_,M5,M6,0,H3,H3,300,_,0,M5,700,300,M6,_,_,_,_,_,
		 H1,H2,H3,0,H6,H5,300,_,0,H6,H5,300,_,0,H6,H5,300,_,0,H2,H3,300,H3,0,H6,H5,300,_,0,H6,H5,300,_,0,H6,H5,300,_,0,H2,H3,300,H2,0,H1,M6,300,_,0,H1,H1,300,H2,0,H1,300,M6,700,0,_,300,H1,700,H3,_,0,H3,H4,H3,H2,H3,300,H2,700,
		 H1,H2,H3,0,H6,H5,_,H6,H5,_,H6,H5,300,_,H3,H3,0,H6,H5,_,H6,H5,_,H6,H5,700,300,H3,700,H2,0,H1,M6,700,300,
		 H3,700,H2,0,H1,300,M6,700,H1,H1,_,_,_,_,_,
		 0,M6,300,H3,700,H2,0,H1,M6,700,300,H3,H2,700,300,0,H1,M6,300,700,H1,H1,_,_,
		 0,L7,M1,M2,M3,300,L3,0,M5,M3,300,L2,L5,2,_,0,L7,M1,M2,M3,300,L2,0,M5,M3,M2,M3,M1,M2,L7,M1,300,L5,0,L7,M1,M2,M3,300,L3,0,M5,M3,300,L2,L5,2,_,
		 0,M6,M3,M2,L6,M3,L6,M2,M3,L6,_,_,_,
		 M2,700,0,M1,300,M2,700,0,M1,300,M2,M3,M5,0,M3,700,300,M2,700,0,M1,300,M2,700,0,M1,M2,M3,M2,M1,300,L5,_,
		 M2,700,0,M1,300,M2,700,0,M1,300,M2,M3,M5,0,M3,700,300,M2,700,0,M3,300,M2,0,M1,700,300,M2,_,_,_,
		 M2,700,0,M1,300,M2,700,0,M1,300,M2,M3,M5,0,M3,700,300,M2,700,0,M3,300,M2,0,M1,700,300,L6,_,
		 0,M3,M2,M1,M2,300,M1,_,0,M3,M2,M1,M2,300,M1,700,0,L5,M3,M2,M1,M2,300,M1,_,_,_,
		 M1,M2,M3,M1,M6,0,M5,M6,300,_,700,0,M1,300,M7,0,M6,M7,300,_,_,M7,0,M6,M7,300,_,M3,0,H1,H2,H1,M7,300,M6,M5,M6,0,M5,M6,_,M5,M6,M5,300,M6,0,M5,M2,300,_,0,M5,700,300,M3,_,_,_,
		 M1,M2,M3,M1,M6,0,M5,M6,300,_,700,0,M1,300,M7,0,M6,M7,300,_,_,M7,0,M6,M7,300,_,M3,0,H1,H2,H1,M7,300,M6,M5,M6,0,H3,H3,300,_,M5,M6,0,H3,H3,300,_,0,M5,700,300,M6,_,_,_,_,_,
		 H1,H2,H3,0,H6,H5,300,_,0,H6,H5,300,_,0,H6,H5,300,_,0,H2,H3,300,H3,0,H6,H5,300,_,0,H6,H5,300,_,0,H6,H5,300,_,0,H2,H3,300,H2,0,H1,M6,300,_,0,H1,H1,300,H2,0,H1,300,M6,700,0,_,300,H1,700,H3,_,0,H3,H4,H3,H2,H3,300,H2,700,
		 H1,H2,H3,0,H6,H5,_,H6,H5,_,H6,H5,300,_,H3,H3,0,H6,H5,_,H6,H5,_,H6,H5,700,300,H3,700,H2,0,H1,M6,700,300,
		 H3,700,H2,0,H1,300,M6,700,H1,H1,_,_,_,_,_,
		 H1,H2,H3,0,H6,H5,300,_,0,H6,H5,300,_,0,H6,H5,300,_,0,H2,H3,300,H3,0,H6,H5,300,_,0,H6,H5,300,_,0,H6,H5,300,_,0,H2,H3,300,H2,0,H1,M6,300,_,0,H1,H1,300,H2,0,H1,300,M6,700,0,_,300,H1,700,H3,_,0,H3,H4,H3,H2,H3,300,H2,700,
		 H2,H3,0,H6,H5,_,H6,H5,_,H6,H5,300,_,H3,H3,0,H6,H5,_,H6,H5,_,H6,H5,700,300,H3,700,H2,0,H1,M6,700,300,
		 H3,700,H2,0,H1,300,M6,700,H1,H1,_,_,_,_,_,
		 H1,H2,H3,0,H6,H5,300,_,0,H6,H5,300,_,0,H6,H5,300,_,0,H2,H3,300,H3,0,H6,H5,300,_,0,H6,H5,300,_,0,H6,H5,300,_,0,H2,H3,300,H2,0,H1,M6,300,_,0,H1,H1,300,H2,0,H1,300,M6,700,0,_,300,H1,700,H3,_,0,H3,H4,H3,H2,H3,300,H2,700,
		 H1,H2,H3,0,H6,H5,_,H6,H5,_,H6,H5,300,_,H3,H3,0,H6,H5,_,H6,H5,_,H6,H5,700,300,H3,700,H2,0,H1,M6,700,300,
		 H3,700,H2,0,H1,300,M6,700,H1,H1,_,_,_,_,_,
		 0,M6,300,H3,700,H2,0,H1,M6,700,300,H3,H2,700,300,0,H1,M6,300,700,H1,H1,_,_,_,_,_,_,_,
		};

		for (auto i : wind) {
			if (i == 0) { sleep = 175; continue; }
			if (i == 700) { Sleep(175); continue; }
			if (i == 300) { sleep = 350; continue; }
			if (i == _) {
				Sleep(350);
				continue;
			}
			// if (i == 900) volume += 100;
			voice = (volume << 16) + ((i) << 8) + 0x90;
			midiOutShortMsg(handle, voice);
			//cout << voice << endl;
			Sleep(sleep);// midiOutShortMsg(handle, 0x7BB0);
		}
		midiOutClose(handle);

	}
}